package sync_director_material_audit_data

import (
	"cid-media-api/global"
	"cid-media-api/models"
	"encoding/json"
	"fmt"
	"github.com/google/uuid"
	"github.com/robfig/cron/v3"
	"github.com/samber/lo"
	"log"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

type SyncDirectorMaterialAuditCommand struct {
	startDate string
	endDate   string
}

type MaterialDetail struct {
	AdvertiserID       string `json:"advertiser_id"`
	MaterialID         string `json:"material_id"`
	MaterialStatusInit string `json:"material_status_init"`
}

type ReportData struct {
	Key             string  `json:"key,omitempty"`
	MediaID         int     `json:"media_id,omitempty"`
	MaterialID      string  `json:"material_id,omitempty"`
	MaterialName    string  `json:"material_name,omitempty"`
	VideoID         string  `json:"video_id,omitempty"`
	AdvertiserID    string  `json:"advertiser_id,omitempty"`
	AdvertiserName  string  `json:"advertiser_name,omitempty"`
	PromotionID     string  `json:"promotion_id,omitempty"`
	PromotionName   string  `json:"promotion_name,omitempty"`
	AuditStatus     int     `json:"audit_status"`
	AuditStatusInit int     `json:"audit_status_init"`
	Cost            float64 `json:"cost"`
	Gmv             float64 `json:"gmv"`
	Roi             string  `json:"roi"`
	Click           int     `json:"click"`
	Show            int     `json:"show"`
	Convert         int     `json:"convert"`
	ValidPlay       int     `json:"valid_play"`
	TotalPlay       int     `json:"total_play"`
}

func GetMaterialAuditDataByDirector(date string, director models.CmsUser) {
	directorId := director.ID

	var distinctOriginFiles []models.File
	// 获取去重的源文件
	global.SucaiDb.
		Model(models.File{}).
		Where("created_at_date = ? "+
			"AND is_fission = 0 "+
			"AND clone_id = 0 "+
			"AND video_type = 'full' "+
			"AND video_director = ? "+
			"AND creator > 0 "+
			"AND deleted_at IS NULL ",
			date, directorId).
		Group("name").
		Select("MIN(id) as id, MIN(created_at_date) as created_at_date, ANY_VALUE(file_md5) as file_md5, name").
		Scan(&distinctOriginFiles)

	if len(distinctOriginFiles) == 0 {
		return
	}

	var existedFileIds []int
	global.SucaiDb.
		Model(models.DirectorMaterialAuditData{}).
		Where("file_create_date = ? "+
			"AND derive_type = 'NONE' "+
			"AND director_id = ? ", date, directorId).
		Select("file_id").
		Find(&existedFileIds)

	distinctOriginFileIds := lo.Map(distinctOriginFiles, func(file models.File, index int) int {
		return file.ID
	})

	fileIdsToCleanUp, _ := lo.Difference(existedFileIds, distinctOriginFileIds)

	// 清理已经失效的源文件 手动删除的同名文件不再纳入统计范畴
	if len(fileIdsToCleanUp) > 0 {
		global.SucaiDb.Model(models.DirectorMaterialAuditData{}).
			Where("file_id IN (?)", fileIdsToCleanUp).
			Delete(&models.DirectorMaterialAuditData{})

		// 删除统计时该源文件的衍生文件记录
		global.SucaiDb.Model(models.DirectorMaterialAuditData{}).
			Where("derive_from IN (?)", fileIdsToCleanUp).
			Delete(&models.DirectorMaterialAuditData{})
	}

	// 获取该编导所有的文件
	var allFiles []models.File
	global.SucaiDb.
		Model(models.File{}).
		Where("created_at_date >= ? "+
			"AND video_director = ? "+
			"AND video_type IN ('full', 'fission') "+
			"AND creator > 0",
			date, directorId).
		Find(&allFiles)

	fileIds := lo.Map(allFiles, func(file models.File, index int) int {
		return file.ID
	})

	// 获取最新的推送任务
	filePushTasks := getFilePushTasksInBatches(fileIds, 20000)

	mediaAccountIds := lo.Uniq(lo.Map(filePushTasks, func(task models.FilePushTask, index int) int {
		return task.MediaAccountID
	}))

	var mediaAccounts []models.MediaAccount
	global.CidDb.
		Model(models.MediaAccount{}).
		Where("id IN ?", mediaAccountIds).
		Select("id, advertiser_id, advertiser_name").
		Find(&mediaAccounts)

	cidAdvAccountMap := make(map[int]models.MediaAccount)
	for _, account := range mediaAccounts {
		cidAdvAccountMap[account.ID] = account
	}

	materialIds := lo.Uniq(lo.Map(filePushTasks, func(task models.FilePushTask, index int) string {
		return task.MaterialID
	}))

	materialDetails := getMaterialDetailsInBatches(materialIds, 20000)

	materialStatusInitMap := lo.GroupBy(materialDetails, func(item MaterialDetail) string {
		return item.MaterialID
	})

	// 获取素材最新数据
	materialAuditLatestData := getLatestMaterialDataInBatches(directorId, materialIds, 20000)

	// 获取素材合计数据
	materialAuditSumData := getSumMaterialDataInBatches(directorId, materialIds, 20000)

	// 遍历源文件
	for _, file := range distinctOriginFiles {
		var directorMaterialAuditData []models.DirectorMaterialAuditData

		// 初始化源视频数据
		originData := initializeData(director, file)

		// 获取衍生文件
		derivedFiles := lo.Filter(allFiles, func(item models.File, index int) bool {
			return strings.Contains(item.Name, file.Name) && item.FileMD5 == file.FileMD5
		})

		originData.DerivedFileCount = len(derivedFiles)

		for _, derivedFile := range derivedFiles {
			// 初始化衍生视频数据
			derivedData := initializeDerivedData(director, file, derivedFile)

			// 获取最新的推送任务
			latestPushTasks := lo.Filter(filePushTasks, func(task models.FilePushTask, index int) bool {
				return task.FileID == derivedFile.ID
			})

			var reportData []ReportData

			for _, latestPushTask := range latestPushTasks {
				processPushTaskData(latestPushTask, cidAdvAccountMap, materialAuditLatestData, materialAuditSumData, &derivedData, &originData, materialStatusInitMap, &reportData)
			}

			// 如果衍生文件过审 则源文件审核成功数+1 而不是按reportRows来计算
			if derivedData.AuditStatus == 1 {
				originData.AuditSuccessCount += 1
			}

			if len(reportData) > 0 {
				reportDataByteArr, _ := json.Marshal(reportData)
				derivedData.ReportData = string(reportDataByteArr)
			}

			derivedData.Roi = calculateROI(derivedData.Cost, derivedData.Gmv)
			directorMaterialAuditData = append(directorMaterialAuditData, derivedData)
		}

		// 计算源文件ROI
		originData.Roi = calculateROI(originData.Cost, originData.Gmv)
		directorMaterialAuditData = append(directorMaterialAuditData, originData)

		// 批量插入数据
		bulkInsertData(directorMaterialAuditData)
	}
}

func initializeData(director models.CmsUser, file models.File) models.DirectorMaterialAuditData {
	fileDatePrefixStr := lo.Substring(file.Name, 0, 6)
	fileDatePrefixTime, err := time.Parse("060102", fileDatePrefixStr)

	fileDatePrefix := "1970-01-01"
	if err == nil {
		fileDatePrefix = fileDatePrefixTime.Format(time.DateOnly)
	}

	return models.DirectorMaterialAuditData{
		Key:               uuid.NewString(),
		DirectorID:        director.ID,
		DirectorName:      director.RealName,
		GroupID:           director.GroupID,
		TeamID:            director.TeamID,
		FileCreateDate:    lo.Substring(file.CreatedAtDate, 0, 10),
		FileID:            file.ID,
		FileName:          file.Name,
		FileDatePrefix:    fileDatePrefix,
		AuditStatus:       0,
		Cost:              0,
		Gmv:               0,
		Click:             0,
		Show:              0,
		Convert:           0,
		ValidPlay:         0,
		TotalPlay:         0,
		PushStatus:        0,
		AuditSuccessCount: 0,
		DeriveFrom:        0,
		DeriveType:        "NONE",
		AuditStatusOrigin: 0,
		ReportData:        "[]",
	}
}

func initializeDerivedData(director models.CmsUser, file models.File, derivedFile models.File) models.DirectorMaterialAuditData {
	fileDatePrefixStr := lo.Substring(file.Name, 0, 6)
	fileDatePrefixTime, err := time.Parse("060102", fileDatePrefixStr)

	fileDatePrefix := "1970-01-01"
	if err == nil {
		fileDatePrefix = fileDatePrefixTime.Format(time.DateOnly)
	}

	return models.DirectorMaterialAuditData{
		Key:               uuid.NewString(),
		DirectorID:        director.ID,
		DirectorName:      director.RealName,
		GroupID:           director.GroupID,
		TeamID:            director.TeamID,
		FileCreateDate:    lo.Substring(file.CreatedAtDate, 0, 10),
		FileID:            derivedFile.ID,
		FileName:          derivedFile.Name,
		FileDatePrefix:    fileDatePrefix,
		AuditStatus:       0,
		Cost:              0,
		Gmv:               0,
		Click:             0,
		Show:              0,
		Convert:           0,
		ValidPlay:         0,
		TotalPlay:         0,
		PushStatus:        0,
		AuditSuccessCount: 0,
		DeriveFrom:        file.ID,
		DeriveType:        determineDerivedType(file, derivedFile),
		AuditStatusOrigin: 0,
		ReportData:        "[]",
	}
}

func determineDerivedType(file models.File, derivedFile models.File) string {
	if derivedFile.IsFission == 1 {
		return "FISSION" // 裂变文件
	} else if derivedFile.CloneID > 0 {
		if derivedFile.CloneID == file.ID {
			return "CLONED_ORIGIN" // 复制源文件
		} else {
			return "CLONED_FISSION" // 复制裂变文件
		}
	} else if derivedFile.Name == file.Name {
		if derivedFile.ID == file.ID {
			return "ORIGIN" // 原始源文件
		} else {
			return "DUPLICATE" // 同名源文件
		}
	} else {
		return "UNKNOWN" // 未知类型(理论上不应该存在)
	}
}

func processPushTaskData(latestPushTask models.FilePushTask, cidAdvAccountMap map[int]models.MediaAccount,
	materialAuditLatestData []models.CmsReportDayMaterial,
	materialAuditSumData []models.CmsReportDayMaterial,
	derivedData *models.DirectorMaterialAuditData,
	originData *models.DirectorMaterialAuditData,
	materialStatusInitMap map[string][]MaterialDetail,
	reportData *[]ReportData) {
	// 获取最新的广告主数据
	advAccount := cidAdvAccountMap[latestPushTask.MediaAccountID]

	// 存在推送任务
	derivedData.PushStatus = 1
	originData.PushStatus = 1

	pushTaskDataRow := ReportData{
		MediaID:        latestPushTask.MediaID,
		MaterialID:     latestPushTask.MaterialID,
		MaterialName:   derivedData.FileName,
		VideoID:        latestPushTask.VideoID,
		AdvertiserID:   strconv.FormatInt(advAccount.AdvertiserId, 10),
		AdvertiserName: advAccount.AdvertiserName,
	}

	// 获取审核数据
	latestAuditReportDataList := lo.Filter(materialAuditLatestData, func(data models.CmsReportDayMaterial, index int) bool {
		return data.MaterialID == latestPushTask.MaterialID
	})
	sumAuditReportDataList := lo.Filter(materialAuditSumData, func(data models.CmsReportDayMaterial, index int) bool {
		return data.MaterialID == latestPushTask.MaterialID
	})

	fillReportData(latestAuditReportDataList, sumAuditReportDataList, pushTaskDataRow, derivedData, originData, materialStatusInitMap, reportData)
}

func fillReportData(
	latestAuditReportDataList []models.CmsReportDayMaterial,
	sumAuditReportDataList []models.CmsReportDayMaterial,
	pushTaskDataRow ReportData,
	derivedData *models.DirectorMaterialAuditData,
	originData *models.DirectorMaterialAuditData,
	materialStatusInitMap map[string][]MaterialDetail,
	reportData *[]ReportData) {

	var reportRows []ReportData

	if len(latestAuditReportDataList) > 0 && len(sumAuditReportDataList) > 0 {
		for _, latestData := range latestAuditReportDataList {
			promotionId := latestData.PromotionID

			// 过滤广告主ID不匹配的数据
			if latestData.AdvertiserID != pushTaskDataRow.AdvertiserID {
				continue
			}

			// 理论上应该一一对应
			sumData, isExist := lo.Find(sumAuditReportDataList, func(data models.CmsReportDayMaterial) bool {
				return data.PromotionID == promotionId
			})
			if !isExist {
				continue
			}

			// 回溯到源文件
			if derivedData.DeriveType == "ORIGIN" ||
				derivedData.DeriveType == "DUPLICATE" ||
				derivedData.DeriveType == "CLONED_ORIGIN" {
				originData.AuditStatusInitOrigin = 1
			}

			//填充单条报表数据
			reportDataRow := ReportData{
				MediaID:         pushTaskDataRow.MediaID,
				MaterialID:      pushTaskDataRow.MaterialID,
				MaterialName:    pushTaskDataRow.MaterialName,
				VideoID:         pushTaskDataRow.VideoID,
				AdvertiserID:    pushTaskDataRow.AdvertiserID,
				AdvertiserName:  pushTaskDataRow.AdvertiserName,
				AuditStatusInit: 1,
				Key:             uuid.NewString(),
				PromotionID:     promotionId,
				PromotionName:   latestData.PromotionName,
				AuditStatus:     latestData.MaterialStatus,
				Cost:            sumData.Cost,
				Gmv:             sumData.InAppOrderGMV,
				Click:           sumData.Click,
				Show:            sumData.Show,
				Convert:         sumData.Convert,
				ValidPlay:       sumData.ValidPlay,
				TotalPlay:       sumData.TotalPlay,
			}

			reportDataRow.Roi = calculateROI(reportDataRow.Cost, reportDataRow.Gmv)

			reportRows = append(reportRows, reportDataRow)

			if reportDataRow.AuditStatus == 1 {
				derivedData.AuditStatus = 1
				originData.AuditStatus = 1

				if derivedData.DeriveType == "ORIGIN" ||
					derivedData.DeriveType == "DUPLICATE" ||
					derivedData.DeriveType == "CLONED_ORIGIN" {
					originData.AuditStatusOrigin = 1
				}
			}

			accumulatedData(originData, derivedData, reportDataRow)
		}
	}

	// 填充报表数据
	*reportData = append(*reportData, reportRows...)

	// 报表数据为空
	if len(reportRows) == 0 {
		pushTaskDataRow.Key = uuid.NewString()

		pushTaskDataRow.AuditStatus = 0     // 推送任务审核状态 未产生报表数据设为0
		pushTaskDataRow.AuditStatusInit = 0 // 初始推送任务审核状态 初始值设为0
		if lo.HasKey(materialStatusInitMap, pushTaskDataRow.MaterialID) {
			materialDetail := materialStatusInitMap[pushTaskDataRow.MaterialID]

			if lo.SomeBy(materialDetail, func(item MaterialDetail) bool {
				return item.AdvertiserID == pushTaskDataRow.AdvertiserID
			}) {
				// 如果存在同广告主账户下初始审核状态为OK的素材 初始审核状态设为1
				pushTaskDataRow.AuditStatusInit = 1

				// 如果该衍生文件为源文件 或者复制的源文件 或者同名的源文件
				if derivedData.DeriveType == "ORIGIN" ||
					derivedData.DeriveType == "DUPLICATE" ||
					derivedData.DeriveType == "CLONED_ORIGIN" {
					// 则认为源文件的初始审核状态为1
					originData.AuditStatusInitOrigin = 1
				}
			}
		}

		pushTaskDataRow.Roi = "0" // 推送任务ROI 设为0

		// 填充推送数据
		*reportData = append(*reportData, pushTaskDataRow)
	}
}

func accumulatedData(originData *models.DirectorMaterialAuditData, derivedData *models.DirectorMaterialAuditData, reportDataRow ReportData) {
	derivedData.Cost += reportDataRow.Cost
	derivedData.Gmv += reportDataRow.Gmv
	derivedData.Click += reportDataRow.Click
	derivedData.Show += reportDataRow.Show
	derivedData.Convert += reportDataRow.Convert
	derivedData.ValidPlay += reportDataRow.ValidPlay
	derivedData.TotalPlay += reportDataRow.TotalPlay

	originData.Cost += reportDataRow.Cost
	originData.Gmv += reportDataRow.Gmv
	originData.Click += reportDataRow.Click
	originData.Show += reportDataRow.Show
	originData.Convert += reportDataRow.Convert
	originData.ValidPlay += reportDataRow.ValidPlay
	originData.TotalPlay += reportDataRow.TotalPlay
}

func calculateROI(cost, gmv float64) string {
	if cost == 0 {
		return "0"
	}
	return fmt.Sprintf("%.2f", gmv/cost)
}

func bulkInsertData(data []models.DirectorMaterialAuditData) {

	chunks := lo.Chunk(data, 500)

	var table string
	table = (&models.DirectorMaterialAuditDataTempDaily{}).TableName()

	for _, chunk := range chunks {
		global.SucaiDb.Table(table).Create(chunk)
	}
}

func getFilePushTasksInBatches(fileIds []int, batchSize int) []models.FilePushTask {
	var allTasks []models.FilePushTask
	for i := 0; i < len(fileIds); i += batchSize {
		end := i + batchSize
		if end > len(fileIds) {
			end = len(fileIds)
		}
		batch := fileIds[i:end]

		var batchTasks []models.FilePushTask
		global.SucaiDb.Raw(`
            SELECT * FROM(
                SELECT media_id, file_id, material_id, media_account_id, video_id,
                ROW_NUMBER() OVER (
                    PARTITION BY media_id, file_id, material_id, media_account_id 
                    ORDER BY finish_at DESC) AS row_num
                FROM file_push_tasks
                WHERE file_id IN (?) AND finish_at IS NOT NULL AND status = 1
            ) AS t
            WHERE row_num = 1`, batch).Scan(&batchTasks)

		allTasks = append(allTasks, batchTasks...)
	}
	return allTasks
}

func getMaterialDetailsInBatches(materialIds []string, batchSize int) []MaterialDetail {
	var allMaterialDetails []MaterialDetail

	for i := 0; i < len(materialIds); i += batchSize {
		end := i + batchSize
		if end > len(materialIds) {
			end = len(materialIds)
		}

		var batchMaterialDetails []MaterialDetail
		global.CidDb.
			Table("media_material_detail").
			Where("material_id IN ?", materialIds[i:end]).
			Where("material_status_init = 'MATERIAL_STATUS_OK' OR material_status = 'PASS'").
			Find(&batchMaterialDetails)

		allMaterialDetails = append(allMaterialDetails, batchMaterialDetails...)
	}

	return allMaterialDetails
}

func getLatestMaterialDataInBatches(directorId int, materialIds []string, batchSize int) []models.CmsReportDayMaterial {
	var allData []models.CmsReportDayMaterial
	for i := 0; i < len(materialIds); i += batchSize {
		end := i + batchSize
		if end > len(materialIds) {
			end = len(materialIds)
		}
		batchIds := materialIds[i:end]

		var batchData []models.CmsReportDayMaterial
		global.SucaiDb.
			Raw(`
            SELECT * FROM (
                SELECT 
                    material_id,
                    video_id,
                    advertiser_id,
                    promotion_id,
                    material_name,
                    advertiser_name,
                    promotion_name,
                    material_status,
                    ROW_NUMBER() OVER (
                        PARTITION BY material_id, material_name, video_id, advertiser_id, promotion_id
                        ORDER BY tdate DESC)
                        AS row_num
                FROM cms_report_day_material
                WHERE material_id IN (?) AND cms_director_id = ?
            )AS t
            WHERE row_num = 1`,
				batchIds, directorId).
			Scan(&batchData)

		allData = append(allData, batchData...)
	}
	return allData
}

func getSumMaterialDataInBatches(directorId int, materialIds []string, batchSize int) []models.CmsReportDayMaterial {
	var allData []models.CmsReportDayMaterial

	for i := 0; i < len(materialIds); i += batchSize {
		end := i + batchSize
		if end > len(materialIds) {
			end = len(materialIds)
		}

		var batchData []models.CmsReportDayMaterial
		global.SucaiDb.
			Model(models.CmsReportDayMaterial{}).
			Where("cms_director_id = ? "+
				"AND material_id IN (?)",
				directorId, materialIds[i:end]).
			Select("material_id, " +
				"material_name, " +
				"video_id, " +
				"advertiser_id, " +
				"promotion_id, " +
				"SUM(cost) as cost, " +
				"SUM(in_app_order_gmv) as in_app_order_gmv, " +
				"SUM(click) as click, " +
				"SUM(`show`) as `show`, " +
				"SUM(`convert`) as `convert`, " +
				"SUM(valid_play) as valid_play, " +
				"SUM(total_play) as total_play").
			Group("material_id, " +
				"material_name, " +
				"video_id, " +
				"advertiser_id, " +
				"promotion_id").
			Find(&batchData)

		allData = append(allData, batchData...)
	}

	return allData
}

func syncMaterialAuditData(date string, logger *log.Logger) {
	groupIds := []int{1028, 1029, 1036, 1054} // 事业部门

	for _, groupId := range groupIds {
		logger.Println("-------------------------------------------")
		logger.Printf("开始获取 %s 部门 %d 的编导素材审核信息\n", date, groupId)

		var directors []models.CmsUser

		// 获取编导人员名单
		global.SucaiDb.Where("group_id = ? and type = 2 and status = 1", groupId).Find(&directors)

		directorUIds := lo.Map(directors, func(director models.CmsUser, index int) int {
			return director.UID
		})

		type sysUser struct {
			UID    int `json:"uid"`
			TeamID int `json:"team_id"`
		}

		var directorUsers []sysUser

		global.CidDb.
			Table("sys_users").
			Where("uid in (?)", directorUIds).
			Select([]string{"uid, team_id"}).
			Find(&directorUsers)

		// 如果临时表已经存在，则删除
		if global.SucaiDb.Migrator().HasTable(&models.DirectorMaterialAuditDataTempDaily{}) {
			err := global.SucaiDb.Migrator().DropTable(&models.DirectorMaterialAuditDataTempDaily{})
			if err != nil {
				logger.Printf("删除已经存在的临时表失败: %s\n", err)
			}
		}

		// 创建临时表
		err := global.SucaiDb.Migrator().CreateTable(&models.DirectorMaterialAuditDataTempDaily{})
		if err != nil {
			logger.Printf("创建临时表失败: %s\n", err)
		}

		wg := sync.WaitGroup{}

		// 按编导人员获取
		for _, director := range directors {
			wg.Add(1)
			go func(director models.CmsUser) {
				defer wg.Done()
				directorUser, _ := lo.Find(directorUsers, func(user sysUser) bool {
					return user.UID == director.UID
				})
				director.TeamID = directorUser.TeamID

				logger.Printf("开始获取部门 %d 的编导人员 %s (ID: %d) 的素材审核信息\n", director.GroupID, director.RealName, director.ID)
				GetMaterialAuditDataByDirector(date, director)
				logger.Printf("获取部门 %d 的编导人员 %s (ID: %d) 的素材审核信息完成\n", director.GroupID, director.RealName, director.ID)
			}(director)
		}

		wg.Wait()

		// 将临时表中的新数据更新至原表中
		logger.Printf("正在从临时表向原表更新 %s 的编导审核统计报表数据...\n", date)
		global.SucaiDb.Exec(
			fmt.Sprintf(
				"INSERT INTO %s (`key`, director_id, director_name, group_id, team_id, file_create_date, file_id, file_name, "+
					"				file_date_prefix, audit_status_init_origin, "+
					"               audit_status, cost, gmv, roi, push_status, audit_success_count, derive_from, "+
					"               derived_file_count, derive_type, report_data,audit_status_origin, click, "+
					"               `show`, `convert`, valid_play, total_play, created_at, updated_at) "+
					"SELECT `key`, director_id, director_name, group_id, team_id, file_create_date, file_id, file_name, "+
					"	   file_date_prefix, audit_status_init_origin, "+
					"      audit_status, cost, gmv, roi, push_status, audit_success_count, derive_from, "+
					"      derived_file_count, derive_type, report_data, audit_status_origin, click, "+
					"      `show`, `convert`, valid_play, total_play, created_at, updated_at "+
					"FROM %s "+
					"ON DUPLICATE KEY UPDATE "+
					"	`key` = VALUES(`key`), "+
					"	director_id = VALUES(director_id), "+
					"	director_name = VALUES(director_name), "+
					"	group_id = VALUES(group_id), "+
					"	team_id = VALUES(team_id), "+
					"	file_create_date = VALUES(file_create_date), "+
					"	file_name = VALUES(file_name), "+
					"	file_date_prefix = VALUES(file_date_prefix), "+
					"	audit_status_init_origin = VALUES(audit_status_init_origin), "+
					"	audit_status = VALUES(audit_status), "+
					"	cost = VALUES(cost), "+
					"	gmv = VALUES(gmv), "+
					"	roi = VALUES(roi), "+
					"	push_status = VALUES(push_status), "+
					"	audit_success_count = VALUES(audit_success_count), "+
					"	derived_file_count = VALUES(derived_file_count), "+
					"	derive_type = VALUES(derive_type), "+
					"	report_data = VALUES(report_data), "+
					"	audit_status_origin = VALUES(audit_status_origin), "+
					"	click = VALUES(click), "+
					"	`convert` = VALUES(`convert`), "+
					"	`show` = VALUES(`show`), "+
					"	valid_play = VALUES(valid_play), "+
					"	total_play = VALUES(total_play), "+
					"	created_at = VALUES(created_at), "+
					"	updated_at = VALUES(updated_at)",
				(&models.DirectorMaterialAuditData{}).TableName(), (&models.DirectorMaterialAuditDataTempDaily{}).TableName()))

		err = global.SucaiDb.Migrator().DropTable(&models.DirectorMaterialAuditDataTempDaily{})
		if err != nil {
			logger.Printf("删除临时表失败: %s\n", err)
		}

		logger.Printf(" %s 部门 %d 的编导素材审核信息更新完毕\n", date, groupId)
		logger.Println("-------------------------------------------")
	}
}

func Execute(startDate, endDate string, logger *log.Logger) {
	logger.Println("开始生成并更新的编导素材审核信息")

	// 默认今日
	if startDate == "" {
		startDate = time.Now().Format(time.DateOnly)
	}
	if endDate == "" {
		endDate = time.Now().Format(time.DateOnly)
	}

	logger.Printf("日期范围：从 %s 到 %s\n", startDate, endDate)
	logger.Printf("开始时间：%s\n", time.Now().Format(time.DateTime))

	start, _ := time.Parse(time.DateOnly, startDate)
	end, _ := time.Parse(time.DateOnly, endDate)

	// 判断日期顺序
	if start.After(end) {
		logger.Println("开始日期不能晚于结束日期")
		return
	}

	// 遍历日期范围
	current := end
	for !current.Before(start) {
		date := current.Format(time.DateOnly)
		logger.Printf("当前日期: %s\n", date)

		syncMaterialAuditData(date, logger)
		current = current.AddDate(0, 0, -1)
	}

	logger.Printf("结束时间：%s\n", time.Now().Format(time.DateTime))
	logger.Println("素材审核统计信息生成并更新完成")
}

func Run(cronSpec string) {
	c := cron.New()
	c.AddFunc(cronSpec, func() {
		logFile, err := os.OpenFile("/www/logs/cid-media-api/crontab/sync_director_material_audit_data_"+time.Now().Format(time.DateOnly)+".log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			log.Fatal(err)
		}
		defer logFile.Close()

		logger := log.New(logFile, "", log.LstdFlags)
		// 默认跑近五天
		endDate := time.Now().Format(time.DateOnly)
		startDate := time.Now().AddDate(0, 0, -4).Format(time.DateOnly)
		Execute(startDate, endDate, logger)
	})

	c.Run()
}
